﻿/*******************************************************************
 *     JameE
 *******************************************************************
  Copyright 2010 Clifford Champion and JameE contributors.
  
  This file is part of JameE.
  
  JameE is free software: you can redistribute it and/or modify
  it under the terms of the GNU General Public License as published by
  the Free Software Foundation, either version 3 of the License, or
  (at your option) any later version.
  
  JameE is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  GNU General Public License for more details.
  
  You should have received a copy of the GNU General Public License
  along with JameE.  If not, see <http://www.gnu.org/licenses/>.
 ******************************************************************/
 
 
/// <reference path="~/Base/Classer.js" />
/// <reference path="~/Base/IncludeLoader.js" />

$class(
"JameE.Math.Matrix",
{
	/////////////////////
	// FIELDS
	/////////////
	_arr_fValues: null,
	_iRows: null,
	_iColumns: null,


	/////////////////////
	// CONSTRUCTOR
	/////////////
	_ctor: function () {
		this._arr_fValues = [];

		this._iRows = $argument("rows", "number") || 0;
		this._iColumns = $argument("columns", "number") || 0;

		this.setZero();
	},


	/////////////////////
	// METHODS
	/////////////
	getNumRows: function () {
		return this._iRows;
	},

	getNumColumns: function () {
		return this._iColumns;
	},

	setZero: function () {
		var iTotalValues = this._iColumns * this._iRows;

		for (var i = 0; i < iTotalValues; ++i) {
			this._arr_fValues[i] = 0;
		}
	},

	setIdentity: function () {

		var iMaxSteps = Math.min(this._iColumns, this._iRows);
		this.setZero();
		for (var i = 0; i < iMaxSteps; ++i) {
			this.setValue(i, i, 1.0);
		}

	},

	multiply: function (oMatrixB) {
		/// <summary>UNTESTED. Returns the result of A * B matrix multiplication.</summary>

		if (this._iColumns !== oMatrixB._iRows) {
			throw new Error("Matrix dimensions incompatible.");
		}
		var iRows = this._iRows;
		var iCols = oMatrixB._iColumns;
		var iShared = this._iColumns;
		var oResult = new JameE.Math.Matrix({ rows: this._iRows, columns: oMatrixB._iColumns });
		for (var i = 0; i < iRows; ++i) {
			for (var j = 0; j < iCols; ++j) {
				var fRunningTotal = 0.0;
				for (var u = 0; u < iShared; ++u) {
					fRunningTotal +=
						(this._arr_fValues[i * iShared + u])
						*
						(oMatrixB._arr_fValues[u * iShared + j])
					;
				}
				oResult._arr_fValues[i * iCols + j] = fRunningTotal;
			}
		}

		return oResult;
	},

	equals: function (oOtherMatrix) {
		if (this._iRows !== oOtherMatrix._iRows) {
			return false;
		}

		if (this._iColumns !== oOtherMatrix._iColumns) {
			return false;
		}

		var iTotalValues = this._iColumns * this._iRows;

		for (var i = 0; i < iTotalValues; ++i) {
			if (this._arr_fValues[i] !== oOtherMatrix._arr_fValues[i]) {
				return false;
			}
		}

		return true;
	},

	setValue: function (i, j, fValue) {
		$require_type(fValue, "number");
		this._arr_fValues[i * this._iColumns + j] = fValue;
	},

	getValue: function (i, j) {
		/// <summary>Returns the value at row i, column j.</summary>
		return this._arr_fValues[i * this._iColumns + j];
	},

	toString: function () {
		var strOutput = "";
		var iRows = this._iRows;
		var iCols = this._iCols;
		for (var i = 0; i < iRows; ++i) {
			for (var j = 0; j < iCols; ++j) {
				strOutput += this.getValue(i, j).toString() + "\t";
			}
			strOutput += "\r\n";
		}
		return strOutput;
	}

});


/////////////////////
// METHODS SHORTCUTS
/////////////
$matrix = function (iRows, iCols) { return new JameE.Math.Matrix({ rows: iRows, columns: iCols }); };




$include_notify("Math/Matrix.js");
